package wahadlo.controllers;

import java.util.Set;

import javax.swing.JButton;

import wahadlo.math.Algorithm;
import wahadlo.math.Euler;
import wahadlo.math.Function;
import wahadlo.math.FunctionFactory;
import wahadlo.model.Model;
import wahadlo.model.ModelRecipient;
import wahadlo.model.Point;
import wahadlo.model.StandardModel;

/**
 * Główna klasa zajmująca się obliczeniami i animacją.
 * 
 * @author Koziołek
 * 
 */
/**
 * @author Koziołek
 *
 */
/**
 * @author Koziołek
 * 
 */
class AnimationImpl implements Runnable, Animation {
	/**
	 * czy animacja działa
	 */
	private boolean runnig = false;

	/**
	 * Czy jest zapauzowana
	 */
	private boolean isResume;

	/**
	 * Model przekazywany pomiędzy obiektami
	 */
	private Model model;

	/**
	 * Odbiorcy modelu.
	 */
	private Set<ModelRecipient> modelRecipients;

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Runnable#run()
	 */
	public void run() {
		// długość pojedynczego kroku animacji
		long step = 15;
		// aktualna klatka animacji
		Double cStep = 0.;

		// rodzaj wykresu
		String chartType = (String) model.getProperties().get("chartType");

		// pobieramy odpowiednią funkcję na podstawie rodzaju wykresu.
		// Przekazujemy jej model.
		Function function = FunctionFactory.getFunction(chartType, model);

		// tworzymy algorytm przetwarzania funkcji w tym przypadku euler
		Algorithm algorithm = new Euler(function.getValue(0.), (double) step);

		// punkt startowy
		Double p0 = algorithm.getValue(function, cStep);

		// obiekty używane w "pętli głównej" inicjalizacja poza pętlą.
		StandardModel modelAndView = null;
		Double translation_scale = 5. / ((Double) model.getProperties().get(
				"length"));

		// "pętla główna"
		while (runnig) {
			// jeżeli animacja jest zapauzowan to czekamy
			if (isResume)
				continue;
			// tworzymy model do przenoszenia danych.
			modelAndView = new StandardModel();
			// obliczamy wartość funkcji w pukcie cStep
			p0 = algorithm.getValue(function, cStep);
			// Tworzymy nowy punkt odpowiadający wartości funkcji w punkcie p.
			Point point = new Point(cStep / translation_scale, p0);

			// jeżeli krok jest większy niż 525 (koniec wykresu) to kończymy
			// przetwarzanie
			if (cStep > 525 * translation_scale) {
				stop();
			}

			// dodajemy do modelu punkt
			modelAndView.add("point", point);
			// oraz skalę by zachować wielkość wykresu
			modelAndView.add("translation_scale", translation_scale);
			// ustawiamy model u odbiorcy.

			for (ModelRecipient modelRecipient : modelRecipients)
				modelRecipient.setModel(modelAndView);

			// przechodzimy dokolejnego kroku
			cStep += step;

			// zasypiamy
			try {
				Thread.sleep(step);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * metoda pozwala na zatrzymanie animacji.
	 */
	private void stop() {
		Object startButton = model.getProperties().get("startButton");
		if(startButton instanceof JButton){
			((JButton)startButton).setEnabled(true);
		}
		runnig = false;
	}

	/**
	 * Konstruktor przyjmuje jako parametry model i listę odbiorców. Model
	 * będzie przetwarzany, a odbiorcy informowani o jego zmianach.
	 * 
	 * @param modelAndView
	 * @param modelRecipients
	 */
	public AnimationImpl(Model modelAndView, Set<ModelRecipient> modelRecipient) {
		this.model = modelAndView;
		this.modelRecipients = modelRecipient;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see wahadlo.controllers.Animation#isRunnig()
	 */
	public boolean isRunnig() {
		return runnig;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see wahadlo.controllers.Animation#setRunnig(boolean)
	 */
	public void setRunnig(boolean runnig) {
		this.runnig = runnig;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see wahadlo.controllers.Animation#setResume(boolean)
	 */
	public void setResume(boolean isResume) {
		this.isResume = isResume;
	}

}
